home *** CD-ROM | disk | FTP | other *** search
- /****************************************/
- /* Low-level control of the EMU8000 */
- /* (c) Grinus/ToM, 1996 */
- /* Written for Borland C++ 3.1 */
- /****************************************/
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
-
- #include "awe.h"
-
-
- // --------------- D a t a --------------- //
-
- WORD Port620 = 0; // EMU base port address (0x620 resp. 0x640)
- WORD PortE22; // secondary port address
-
- WORD TbEffectCmd[4] = { AWE_28, AWE_2A, AWE_2C, AWE_2E };
-
- WORD TbEffData1[128] = {
- 0x03FF, 0x0030, 0x07FF, 0x0130, 0x0BFF, 0x0230, 0x0FFF, 0x0330,
- 0x13FF, 0x0430, 0x17FF, 0x0530, 0x1BFF, 0x0630, 0x1FFF, 0x0730,
- 0x23FF, 0x0830, 0x27FF, 0x0930, 0x2BFF, 0x0A30, 0x2FFF, 0x0B30,
- 0x33FF, 0x0C30, 0x37FF, 0x0D30, 0x3BFF, 0x0E30, 0x3FFF, 0x0F30,
- 0x43FF, 0x0030, 0x47FF, 0x0130, 0x4BFF, 0x0230, 0x4FFF, 0x0330,
- 0x53FF, 0x0430, 0x57FF, 0x0530, 0x5BFF, 0x0630, 0x5FFF, 0x0730,
- 0x63FF, 0x0830, 0x67FF, 0x0930, 0x6BFF, 0x0A30, 0x6FFF, 0x0B30,
- 0x73FF, 0x0C30, 0x77FF, 0x0D30, 0x7BFF, 0x0E30, 0x7FFF, 0x0F30,
- 0x83FF, 0x0030, 0x87FF, 0x0130, 0x8BFF, 0x0230, 0x8FFF, 0x0330,
- 0x93FF, 0x0430, 0x97FF, 0x0530, 0x9BFF, 0x0630, 0x9FFF, 0x0730,
- 0xA3FF, 0x0830, 0xA7FF, 0x0930, 0xABFF, 0x0A30, 0xAFFF, 0x0B30,
- 0xB3FF, 0x0C30, 0xB7FF, 0x0D30, 0xBBFF, 0x0E30, 0xBFFF, 0x0F30,
- 0xC3FF, 0x0030, 0xC7FF, 0x0130, 0xCBFF, 0x0230, 0xCFFF, 0x0330,
- 0xD3FF, 0x0430, 0xD7FF, 0x0530, 0xDBFF, 0x0630, 0xDFFF, 0x0730,
- 0xE3FF, 0x0830, 0xE7FF, 0x0930, 0xEBFF, 0x0A30, 0xEFFF, 0x0B30,
- 0xF3FF, 0x0C30, 0xF7FF, 0x0D30, 0xFBFF, 0x0E30, 0xFFFF, 0x0F30
- };
-
- WORD TbEffData2[128] = {
- 0x0C10, 0x8470, 0x14FE, 0xB488, 0x167F, 0xA470, 0x18E7, 0x84B5,
- 0x1B6E, 0x842A, 0x1F1D, 0x852A, 0x0DA3, 0x0F7C, 0x167E, 0x7254,
- 0x0000, 0x842A, 0x0001, 0x852A, 0x18E6, 0x0BAA, 0x1B6D, 0x7234,
- 0x229F, 0x8429, 0x2746, 0x8529, 0x1F1C, 0x06E7, 0x229E, 0x7224,
- 0x0DA4, 0x8429, 0x2C29, 0x8529, 0x2745, 0x07F6, 0x2C28, 0x7254,
- 0x383B, 0x8428, 0x320F, 0x8528, 0x320E, 0x0F02, 0x1341, 0x7264,
- 0x3EB6, 0x8428, 0x3EB9, 0x8528, 0x383A, 0x0FA9, 0x3EB5, 0x7294,
- 0x3EB7, 0x8474, 0x3EBA, 0x8575, 0x3EB8, 0x44C3, 0x3EBB, 0x45C3,
- 0x0000, 0xA404, 0x0001, 0xA504, 0x141F, 0x0671, 0x14FD, 0x0287,
- 0x3EBC, 0xE610, 0x3EC8, 0x0C7B, 0x031A, 0x07E6, 0x3EC8, 0x86F7,
- 0x3EC0, 0x821E, 0x3EBE, 0xD208, 0x3EBD, 0x021F, 0x3ECA, 0x0386,
- 0x3EC1, 0x0C03, 0x3EC9, 0x031E, 0x3ECA, 0x8C4C, 0x3EBF, 0x0C55,
- 0x3EC9, 0xC208, 0x3EC4, 0xBC84, 0x3EC8, 0x0EAD, 0x3EC8, 0xD308,
- 0x3EC2, 0x8F7E, 0x3ECB, 0x0219, 0x3ECB, 0xD26E, 0x3EC5, 0x031F,
- 0x3EC6, 0xC308, 0x3EC3, 0x32FF, 0x3EC9, 0x0265, 0x3EC9, 0x8319,
- 0x1342, 0xD36E, 0x3EC7, 0x33FF, 0x0000, 0x8365, 0x1420, 0x9570
- };
-
- CHORUS_TYPE TbChorusTypes[8] = {
- 0xE600, 0x03F6, 0xBC2C, 0, 0x006D, // Chorus 1
- 0xE608, 0x031A, 0xBC6E, 0, 0x017C, // Chorus 2
- 0xE610, 0x031A, 0xBC84, 0, 0x0083, // Chorus 3
- 0xE620, 0x0269, 0xBC6E, 0, 0x017C, // Chorus 4
- 0xE680, 0x04D3, 0xBCA6, 0, 0x005B, // Feedback Delay
- 0xE6E0, 0x044E, 0xBC37, 0, 0x0026, // Flanger
- 0xE600, 0x0B06, 0xBC00, 0x6E000, 0x0083, // Short Delay
- 0xE6C0, 0x0B06, 0xBC00, 0x6E000, 0x0083 // Short Delay FB
- };
-
- BYTE TbReverbReg[28] = {
- 0x03, 0x05, 0x7F, 0x07, 0x34, 0x36, 0x0F,
- 0x17, 0x1F, 0x27, 0x2F, 0x37, 0x3D, 0x3F,
- 0x41, 0x43, 0x09, 0x0B, 0x11, 0x13, 0x19,
- 0x1B, 0x21, 0x23, 0x29, 0x2B, 0x31, 0x33
- };
-
- WORD TbReverbData[8*28] = {
- 0xB488, 0xA450, 0x9550, 0x84B5, 0x383A, 0x3EB5, 0x72F4, // Room 1
- 0x72A4, 0x7254, 0x7204, 0x7204, 0x7204, 0x4416, 0x4516,
- 0xA490, 0xA590, 0x842A, 0x852A, 0x842A, 0x852A, 0x8429,
- 0x8529, 0x8429, 0x8529, 0x8428, 0x8528, 0x8428, 0x8528,
-
- 0xB488, 0xA458, 0x9558, 0x84B5, 0x383A, 0x3EB5, 0x7284, // Room 2
- 0x7254, 0x7224, 0x7224, 0x7254, 0x7284, 0x4448, 0x4548,
- 0xA440, 0xA540, 0x842A, 0x852A, 0x842A, 0x852A, 0x8429,
- 0x8529, 0x8429, 0x8529, 0x8428, 0x8528, 0x8428, 0x8528,
-
- 0xB488, 0xA460, 0x9560, 0x84B5, 0x383A, 0x3EB5, 0x7284, // Room 3
- 0x7254, 0x7224, 0x7224, 0x7254, 0x7284, 0x4416, 0x4516,
- 0xA490, 0xA590, 0x842C, 0x852C, 0x842C, 0x852C, 0x842B,
- 0x852B, 0x842B, 0x852B, 0x842A, 0x852A, 0x842A, 0x852A,
-
- 0xB488, 0xA470, 0x9570, 0x84B5, 0x383A, 0x3EB5, 0x7284, // Hall 1
- 0x7254, 0x7224, 0x7224, 0x7254, 0x7284, 0x4448, 0x4548,
- 0xA440, 0xA540, 0x842B, 0x852B, 0x842B, 0x852B, 0x842A,
- 0x852A, 0x842A, 0x852A, 0x8429, 0x8529, 0x8429, 0x8529,
-
- 0xB488, 0xA470, 0x9570, 0x84B5, 0x383A, 0x3EB5, 0x7254, // Hall 2
- 0x7234, 0x7224, 0x7254, 0x7264, 0x7294, 0x44C3, 0x45C3,
- 0xA404, 0xA504, 0x842A, 0x852A, 0x842A, 0x852A, 0x8429,
- 0x8529, 0x8429, 0x8529, 0x8428, 0x8528, 0x8428, 0x8528,
-
- 0xB4FF, 0xA470, 0x9570, 0x84B5, 0x383A, 0x3EB5, 0x7234, // Plate
- 0x7234, 0x7234, 0x7234, 0x7234, 0x7234, 0x4448, 0x4548,
- 0xA440, 0xA540, 0x842A, 0x852A, 0x842A, 0x852A, 0x8429,
- 0x8529, 0x8429, 0x8529, 0x8428, 0x8528, 0x8428, 0x8528,
-
- 0xB4FF, 0xA470, 0x9500, 0x84B5, 0x333A, 0x39B5, 0x7204, // Delay
- 0x7204, 0x7204, 0x7204, 0x7204, 0x72F4, 0x4400, 0x4500,
- 0xA4FF, 0xA5FF, 0x8420, 0x8520, 0x8420, 0x8520, 0x8420,
- 0x8520, 0x8420, 0x8520, 0x8420, 0x8520, 0x8420, 0x8520,
-
- 0xB4FF, 0xA490, 0x9590, 0x8474, 0x333A, 0x39B5, 0x7204, // Panning Delay
- 0x7204, 0x7204, 0x7204, 0x7204, 0x72F4, 0x4400, 0x4500,
- 0xA4FF, 0xA5FF, 0x8420, 0x8520, 0x8420, 0x8520, 0x8420,
- 0x8520, 0x8420, 0x8520, 0x8420, 0x8520, 0x8420, 0x8520
- };
-
- WORD TbAweBass[12*3] = {
- 0xD26A, 0xD36A, 0x0000, // -12 dB
- 0xD25B, 0xD35B, 0x0000, // -8
- 0xD24C, 0xD34C, 0x0000, // -6
- 0xD23D, 0xD33D, 0x0000, // -4
- 0xD21F, 0xD31F, 0x0000, // -2
- 0xC208, 0xC308, 0x0001, // 0 (HW default)
- 0xC219, 0xC319, 0x0001, // +2
- 0xC22A, 0xC32A, 0x0001, // +4
- 0xC24C, 0xC34C, 0x0001, // +6
- 0xC26E, 0xC36E, 0x0001, // +8
- 0xC248, 0xC348, 0x0002, // +10
- 0xC26A, 0xC36A, 0x0002 // +12 dB
- };
-
- WORD TbAweTreble[12*9] = {
- 0x821E, 0xC26A, 0x031E, 0xC36A, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001, // -12 dB
- 0x821E, 0xC25B, 0x031E, 0xC35B, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001,
- 0x821E, 0xC24C, 0x031E, 0xC34C, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001,
- 0x821E, 0xC23D, 0x031E, 0xC33D, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001,
- 0x821E, 0xC21F, 0x031E, 0xC31F, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001,
- 0x821E, 0xD208, 0x031E, 0xD308, 0x021E, 0xD208, 0x831E, 0xD308, 0x0002,
- 0x821E, 0xD208, 0x031E, 0xD308, 0x021D, 0xD219, 0x831D, 0xD319, 0x0002,
- 0x821E, 0xD208, 0x031E, 0xD308, 0x021C, 0xD22A, 0x831C, 0xD32A, 0x0002,
- 0x821E, 0xD208, 0x031E, 0xD308, 0x021A, 0xD24C, 0x831A, 0xD34C, 0x0002,
- 0x821E, 0xD208, 0x031E, 0xD308, 0x0219, 0xD26E, 0x8319, 0xD36E, 0x0002, // +8 (HW default)
- 0x821D, 0xD219, 0x031D, 0xD319, 0x0219, 0xD26E, 0x8319, 0xD36E, 0x0002,
- 0x821C, 0xD22A, 0x031C, 0xD32A, 0x0219, 0xD26E, 0x8319, 0xD36E, 0x0002 // +12 dB
- };
-
-
- // --------------- C o d e --------------- //
-
-
- /*
- Read the EMU base address from the BLASTER variable
- */
- WORD GetBaseFromEnv()
- {
- char *p;
- WORD w;
-
- if (!(p = getenv("BLASTER"))
- || !(p = strstr(p, " E"))
- || sscanf(p+2, "%x", &w ) !=1 )
- return 0; // ERROR
- return w; // address
- }
-
- // --------------- Low-level EMU8000 routines --------------- //
-
- /*
- Write the 16-bit EMU register
- */
- void AweWrW(WORD reg, WORD data)
- {
- asm { mov ax, reg // HighBYTE = register index, LowBYTE = G-chan number
-
- mov cx,ax
- mov cl,ch
- and cx,0x6002
- shr ch,3
- add cx,Port620 // CX=port2
-
- and ax,0x1C1F
- shl ah,3
- or al,ah
- xor ah,ah // AX=data1
- mov dx,PortE22 // DX=port1
-
- cli // start of critical section
- out dx,ax
- mov dx,cx // DX=port2
- mov ax, data // AX=data2
- out dx,ax
- sti // end of critical section
- }
- }
-
-
- /*
- Read the 16-bit EMU register
- */
- WORD AweRdW(WORD reg)
- {
- asm { mov ax, reg
- mov cx,ax
- mov cl,ch
- and cx,0x6002
- shr ch,3
- add cx,Port620
- and ax,0x1C1F
- shl ah,3
- or al,ah
- xor ah,ah
- mov dx,PortE22
- cli
- out dx,ax
- mov dx,cx
- in ax,dx
- sti
- }
- #pragma warn -rvl
- }
- #pragma warn +rvl
-
-
- /*
- Write the 32-bit EMU register
- */
- void AweWrD(WORD reg, WORD hdata, WORD ldata )
- {
- asm { mov ax, reg
- mov cx,ax
- mov cl,ch
- and cx,0x6002
- shr ch,3
- add cx,Port620
- and ax,0x1C1F
- shl ah,3
- or al,ah
- xor ah,ah
- mov dx,PortE22
- cli
- out dx,ax
- mov dx,cx
- mov ax,ldata
- out dx,ax
- inc dx
- inc dx
- mov ax,hdata
- out dx,ax
- sti
- }
- }
-
-
- /*
- Read the 32-bit EMU register
- */
- DWORD AweRdD(WORD reg)
- {
- asm { mov ax, reg
- mov cx,ax
- mov cl,ch
- and cx,0x6002
- shr ch,3
- add cx,Port620
- and ax,0x1C1F
- shl ah,3
- or al,ah
- xor ah,ah
- mov dx,PortE22
- cli
- out dx,ax
- mov dx,cx
- in ax,dx
- mov cx,ax
- inc dx
- inc dx
- in ax,dx
- sti
- mov dx,ax
- mov ax,cx
- }
- #pragma warn -rvl
- }
- #pragma warn +rvl
-
-
- /*
- Detect the presence of the EMU8000
- */
- int AweDetect1()
- {
- BYTE b;
- WORD w;
- asm mov dx,Port620
- asm add dx,0x802
- asm mov PortE22,dx
- asm in al,dx
- asm in al,dx
- asm not al
- asm mov b,al
- asm out dx,al // invert the LowByte
- asm in al,dx
- if ( _AL != b)
- return 0; // ERROR
- asm in ax,dx
- asm mov w,ax
- for (b = 128; 1; b--) {
- asm in ax,dx
- if (_AX != w)
- break; // is it changing?
- if (b==0)
- return 0; // if not, then ERROR
- }
- if ( (AweRdW(AWE_5C) & 0x8E) != 0x0C )
- return 0;
- b = ~AweRdW(0x241E) & 0x06;
- w = ~AweRdW(0x241F) & 0x1F;
- AweWrW(0x241E, w | b<<4);
- if ( (AweRdW(0x241E) & 0x06) != b)
- return 0;
- AweWrW(0x241E, w | (~b<<4 & 0x60) );
-
- return 1; // ok
- }
-
-
- /*
- Determine the EMU8000 base port
- */
- int AweDetect()
- {
- if (Port620 == 0) // the address is not forced ?
- Port620 = GetBaseFromEnv(); // then let's try the BLASTER variable
-
- if (Port620 == 0) { // still unknown?
- Port620 = 0x620; // Try 0x620
- if (AweDetect1())
- return 1; // ok
- Port620 += 0x20; // Try 0x640
- }
- return AweDetect1();
- }
-
-
- /*
- Wait for some EMU clocks (1/44100 sec)
- */
- void AweWait(WORD delay)
- {
- WORD t0 = AweRdW(AWE_CLK);
- while ( (WORD)( AweRdW(AWE_CLK) - t0 ) < delay )
- ;
- }
-
-
- void InitEnvelopeEngine()
- {
- for (WORD gchan = 0; gchan<32; gchan++) {
- AweWrW( AWE_Env2Su_Dcy|gchan, 0x0080 );
- AweWrW( AWE_Env1Ho_Att|gchan, 0 );
- AweWrW( AWE_Env1Su_Dcy|gchan, 0 );
- AweWrW( AWE_Pitch |gchan, 0xD000 );
- AweWrW( AWE_FC_Vol |gchan, 0xFF00 );
- AweWrW( AWE_Env1tP_tF |gchan, 0 );
- AweWrW( AWE_Lfo1tP_tF |gchan, 0 );
- AweWrW( AWE_Lfo1tV_F |gchan, 0x0018 );
- AweWrW( AWE_Lfo2tP_F |gchan, 0x0018 );
- AweWrW( AWE_58 |gchan, 0 );
- AweWrW( AWE_Lfo2Dly |gchan, 0 );
- AweWrW( AWE_Lfo1Dly |gchan, 0 );
- AweWrW( AWE_Env2Ho_Att|gchan, 0 );
- AweWrW( AWE_Env2Dly |gchan, 0 );
- AweWrW( AWE_Env1Dly |gchan, 0 );
- }
- }
-
-
- void InitSoundEngine()
- {
- AweWrD(AWE_RdAdrD, 0x8000, 0x0000 );
- AweWrD(AWE_RdAdrD+1, 0x8000, 0x0000 );
- AweWrD(AWE_WrAdrD, 0x8000, 0x0000 );
- AweWrD(AWE_WrAdrD+1, 0x8000, 0x0000 );
-
- for (WORD gchan = 0; gchan<32; gchan++) {
- AweWrD( AWE_DP_Rev_Pan |gchan, 0, 0 );
- AweWrD( AWE_DestV_FC |gchan, 0, 0xFFFF );
- AweWrD( AWE_CurrV_FC |gchan, 0, 0xFFFF );
- AweWrD( AWE_Pan_Loops |gchan, 0, 0 );
- AweWrD( AWE_Cho_Loope |gchan, 0, 0 );
- AweWrD( AWE_CurrPitch |gchan, 0, 0 );
- AweWrD( AWE_Flt_Start |gchan, 0, 0 );
- AweWrD( AWE_14 |gchan, 0, 0 );
- AweWrD( AWE_10 |gchan, 0, 0 );
- AweWrW( AWE_Env1Su_Dcy |gchan, 0x807F );
- AweWrW( AWE_Env2Su_Dcy |gchan, 0x807F );
- }
- }
-
-
- void InitEffects1(WORD near *data)
- {
- int i;
- for (i=0; i<128; i++)
- AweWrW( (i & 0x1F) | TbEffectCmd[i>>5 & 0x07], data[i] );
- }
-
-
- void InitEffects2(WORD near *data)
- {
- int i;
- for (i=0; i<128; i++)
- AweWrW( (i & 0x1F) | TbEffectCmd[i>>5 & 0x07], data[i] | i<<15 );
- }
-
-
- void InitEffectsEngine()
- {
- int i,j;
- InitEffects1(TbEffData1);
- AweWait(0x400);
- for (i=0; i<0x14; i++)
- AweWrD(0x2400|i, 0, 0 );
- InitEffects2(TbEffData1);
- InitEffects2(TbEffData2);
- AweWrD(0x2409, 0, 0 );
- AweWrD(0x240A, 0, 0x0083 );
- AweWrD(0x240D, 0, 0x8000 );
- AweWrD(0x240E, 0, 0 );
- InitEffects1(TbEffData2);
- }
-
-
- /*
- Prepare the last two channels for DRAM refresh and producing the reverb
- and chorus effects for Yamaha OPL-3 synthesizer.
- */
- void InitFMEffects(BYTE reverb, BYTE chorus)
- {
- AweWrW(AWE_Env2Su_Dcy |30, 0x0080 );
- AweWrD(AWE_Pan_Loops |30, 0xFFFF, 0xFFE0 );
- AweWrD(AWE_Cho_Loope |30, 0x00FF | (WORD)chorus<<8, 0xFFE8 );
- AweWrD(AWE_DP_Rev_Pan |30, 0, (WORD)reverb<<8 );
- AweWrD(AWE_CurrPitch |30, 0, 0 );
- AweWrD(AWE_Flt_Start |30, 0x00FF, 0xFFE3 );
-
- AweWrW(AWE_Env2Su_Dcy |31, 0x0080 );
- AweWrD(AWE_Pan_Loops |31, 0x00FF, 0xFFF0 );
- AweWrD(AWE_Cho_Loope |31, 0x00FF | (WORD)chorus<<8, 0xFFF8 );
- AweWrD(AWE_DP_Rev_Pan |31, 0, 0x00FF | (WORD)reverb<<8 );
- AweWrD(AWE_CurrPitch |31, 0, 0x8000);
- AweWrD(AWE_Flt_Start |31, 0x00FF, 0xFFF3 );
-
- asm cli // disable interrupts
- asm mov dx,PortE22
- asm mov ax,0x003E
- asm out dx,ax
-
- asm xchg bx,dx
- asm mov dx,Port620
- asm xor ax,ax
- asm out dx,ax
-
- asm xchg bx,dx // 0xE22
- loop1: asm in ax,dx
- asm test ah,0x10
- asm jz loop1
- loop2: asm in ax,dx
- asm test ah,0x10
- asm jnz loop2 // wait for an edge
-
- asm mov dx,bx
- asm add dx,2 // 0x622
- asm mov ax,0x4828
- asm out dx,ax
-
- asm mov dx,PortE22
- asm mov ax,0x003C
- asm out dx,ax
-
- asm mov dx,bx
- asm add dh,4 // 0xE20
- asm xor ax,ax
- asm out dx,ax
- asm sti // enable interrupts
-
- AweWrD(AWE_DestV_FC |30, 0x8000, 0xFFFF );
- AweWrD(AWE_DestV_FC |31, 0x8000, 0xFFFF );
- }
-
-
- /*
- Prepare some G-channels for the sample upload/download
- rmode = 1 -> odd G-channels for reading
- rmode = 0 -> all G-channels for writing
- */
- void AweEnableRam(int rmode)
- {
- WORD gchan;
- for (gchan=0; gchan<30; gchan++)
- AweWrW( AWE_Env2Su_Dcy |gchan, 0x0080 );
-
- for (gchan=0; gchan<30; gchan++) {
- AweWrD( AWE_DestV_FC |gchan, 0, 0 );
- AweWrD( AWE_CurrV_FC |gchan, 0, 0 );
- AweWrD( AWE_Pan_Loops |gchan, 0, 0 );
- AweWrD( AWE_Cho_Loope |gchan, 0, 0 );
- AweWrD( AWE_DP_Rev_Pan |gchan, 0x4000, 0x0000 );
- AweWrD( AWE_CurrPitch |gchan, 0x4000, 0x0000 );
- // Read (4) / Write (6) mode
- AweWrD( AWE_Flt_Start |gchan, (gchan & rmode) ? 0x0400 : 0x0600, 0 );
- }
- }
-
-
- void AweDisableRam()
- {
- for (WORD gchan=0; gchan<30; gchan++)
- AweWrD( AWE_Flt_Start |gchan, 0, 0 ),
- AweWrW( AWE_Env2Su_Dcy |gchan, 0x807F );
- }
-
-
- /*
- Check the sample RAM size
- This routine does not restore the changed sample data!
- */
- WORD RamCheck()
- {
- WORD DRAMsize; // [KB]
-
- AweEnableRam(1); // we need both to read and write
-
- AweWrD(AWE_WrAdrD, TOPRAM>>16, TOPRAM&0xFFFF ); // 1-st addr in RAM
- AweWrW(AWE_DataW, 0xE5A7 );
- AweWrW(AWE_DataW, 0x1A58 ); // put a mark there
-
- for (DRAMsize=0; DRAMsize<28*1024; ) {
- AweWait(2);
- AweWrD(AWE_RdAdrD, TOPRAM>>16, TOPRAM&0xFFFF ); // back to 1-st addr
- AweRdW(AWE_DataW); // skip the 1-st word
- if (AweRdW(AWE_DataW)!=0xE5A7)
- break;
- if (AweRdW(AWE_DataW)!=0x1A58) // is the mark present?
- break;
- DRAMsize += 32;
- AweWrD(AWE_WrAdrD, (TOPRAM>>16) + (DRAMsize>>7),
- (TOPRAM&0xFFFF) + (DRAMsize<<9) );
- AweWrW(AWE_DataW, 0xFFFF); // clear the mark
- }
-
- AweDisableRam();
-
- return DRAMsize;
- }
-
-
- /*
- Initialization of the EMU8000
- (except the Equalizer and Effect settings)
- */
- int AweInitHw()
- {
- WORD DRAMsize;
-
- if ( (AweRdW(AWE_5C) & 0x0E) != 0x0C)
- return 0; // ERROR
-
- AweWrW( 0x241D, 0x0059 );
- AweWrW( 0x241E, 0x0020 );
- AweWrW( 0x241F, 0 );
-
- InitEnvelopeEngine();
- InitSoundEngine();
- InitEffectsEngine();
-
- InitFMEffects( 102, 51 ); // Reverb 40%, Chorus 20%
-
- DRAMsize = RamCheck();
-
- AweWrW( 0x241F, 0x0006 );
- if (~AweRdW(0x241E) & 0x40)
- return 0; // ERROR
-
- return DRAMsize; // ok
- }
-
-
- /*
- EMU clean-up routine
- (called from 'exit' function)
- */
- void AweTerminate()
- {
- for (WORD gchan=30; gchan--; )
- AweWrW( AWE_Env2Su_Dcy |gchan, 0x807F ); // All Sounds Off
-
- AweWait(2205); // wait 50ms to avoid the reverb-click
-
- InitFMEffects( 102, 51 ); // Reverb & chorus for OPL3 synth
- }
-
-
- /*
- Set the chorus type
- */
- void AweChorusType(int type)
- {
- CHORUS_TYPE *t = TbChorusTypes + type; // type = 0..7
-
- AweWrW(AWE_2C|0x09, t->FbkLevel );
- AweWrW(AWE_2C|0x0C, t->Delay );
- AweWrW(AWE_2E|0x03, t->LfoDepth );
- AweWrD(AWE_24|0x09, HWORD(t->DelayR), (WORD)t->DelayR );
- AweWrD(AWE_24|0x0A, HWORD(t->LfoFreq), (WORD)t->LfoFreq );
- AweWrD(AWE_24|0x0D, 0, 0x8000 );
- AweWrD(AWE_24|0x0E, 0, 0 );
- }
-
-
- /*
- Set the reverb type
- */
- void AweReverbType(int type)
- {
- BYTE b;
- for (int i=0; i<28; i++)
- b = TbReverbReg[i],
- AweWrW( TbEffectCmd[b>>5] | (b & 0x1F), TbReverbData[type*28+i] );
-
- }
-
-
- /*
- Send the values of EMU8000 digital equalizer
- */
- void AweTrebleBass(int bass, int treble)
- {
- // a range is 0..11 (-12dB .. +12dB)
- WORD w;
- WORD *pb = TbAweBass + bass*3;
- WORD *pt = TbAweTreble + treble*9;
-
- AweWrW(AWE_2E | 0x01, pb[0] );
- AweWrW(AWE_2E | 0x11, pb[1] );
- AweWrW(AWE_2C | 0x11, pt[0] );
- AweWrW(AWE_2C | 0x13, pt[1] );
- AweWrW(AWE_2C | 0x1B, pt[2] );
- AweWrW(AWE_2E | 0x07, pt[3] );
- AweWrW(AWE_2E | 0x0B, pt[4] );
- AweWrW(AWE_2E | 0x0D, pt[5] );
- AweWrW(AWE_2E | 0x17, pt[6] );
- AweWrW(AWE_2E | 0x19, pt[7] );
- w = pb[2] + pt[8];
- AweWrW(AWE_2E | 0x15, w + 0x0263 );
- AweWrW(AWE_2E | 0x1D, w - 0x7C9D );
- }
-
-
- /*
- Send the block of 16-bit signed samples to the sample RAM,
- provided that the sample RAM address is already set
- */
- void AweWrBlock(WORD far *buf, WORD num_samps)
- {
- asm mov cx,num_samps
- asm jcxz retdlr
- asm mov dx,PortE22
- asm mov ax,0x003A
- asm out dx,ax
- asm mov dx,Port620
- asm add dh,4
- asm push ds
- asm lds si,buf
- asm cld
- loopdlr16:
- asm lodsw
- asm out dx,ax
- asm loop loopdlr16
- asm pop ds
- retdlr:
- }
-
-
- /*
- Send the NoteOff cmd
- (in fact, it just starts the release phase)
- */
- void NoteOff(int gChan)
- {
- // Start the fastest decay to a zero level
- AweWrW( AWE_Env2Su_Dcy |gChan, 0x807F );
-
- /* ENV1 was not used
- AweWrW( AWE_Env1Su_Dcy |gChan, 0x807F );
- */
- }
-
-
- /*
- The fastest possible destroing of the note
- It can cause a click!
- */
- void CutNote(int gChan)
- {
- AweWrW(AWE_Env2Su_Dcy|gChan, 0x0080); // disable the volume envelope
- AweWrD(AWE_DestV_FC |gChan, 0, 0xFFFF); // dest. volume = 0
- }
-
-
- /*
- Start the new note
- It expects that all necessary values are already prepared.
- */
- void AweNoteOn( int gChan, // 0..29
- BYTE Volume, // log. 255..0 (min..max)
- BYTE Pan, // 00..FF (left..right)
- BYTE Reverb, // lin. 00..FF
- BYTE Chorus, // lin. 00..FF
- WORD AwePitch, // log. 0000..FFFF
- WORD AweLinPitch, // lin. 0000..FFFF
- DWORD Start, // 000000..FFFFFF
- DWORD LoopS, DWORD LoopE // 000000..FFFFFF
- )
- {
- // Send the G-channel params
- AweWrD( AWE_DestV_FC |gChan, 0, 0xFFFF ); // CurrVol=0, CurrFC=0xFFFF
- AweWrW( AWE_Env2Ho_Att |gChan, 0x7F7E); // ENV2 Hold = 0, Attack = 6ms
- AweWrW( AWE_Lfo1Dly |gChan, 0x8000 ); // LFO1 Delay = 0
- AweWrW( AWE_Env1Ho_Att |gChan, 0x7F7F ); // ENV1 Hold & Attack = 0
- AweWrW( AWE_Env1Su_Dcy |gChan, 0x807F ); // ENV1 Sustain & Decay = 0
- AweWrW( AWE_Lfo2Dly |gChan, 0x8000 ); // LFO2 Delay = 0
- AweWrW( AWE_Pitch |gChan, AwePitch ); // Pitch
- AweWrW( AWE_FC_Vol |gChan, 0xFF00|Volume); // FiltCutoff & Volume
- AweWrW( AWE_Env1tP_tF |gChan, 0x0000 ); // ENV1 ToPitch & ToFilter
- AweWrW( AWE_Lfo1tP_tF |gChan, 0x0000 ); // LFO1 ToPitch & ToFilter
- AweWrW( AWE_Lfo1tV_F |gChan, 0x0000 ); // LFO1 ToVolume & Freq
- AweWrW( AWE_Lfo2tP_F |gChan, 0x0000 ); // LFO2 ToPitch & Freq
- AweWrW( AWE_Env1Dly |gChan, 0x8000 ); // ENV1 Delay = 0
- AweWrW( AWE_Env2Dly |gChan, 0x8000 ); // ENV2 Delay = 0
- AweWrD( AWE_CurrV_FC |gChan, 0, 0xFFFF ); // CurrVol=0, CurrFC=max
- AweWrD( AWE_DP_Rev_Pan |gChan, AweLinPitch, // DestPitch
- (WORD)Reverb<<8 // ReverbLevel
- | Pan ); // RightPan
- AweWrD( AWE_Pan_Loops |gChan,
- (WORD)(~Pan) <<8 // LeftPan
- | HWORD(LoopS), (WORD)LoopS ); // LoopS
- AweWrD( AWE_Cho_Loope |gChan, (WORD)Chorus<<8 // Chorus
- | HWORD(LoopE), (WORD)LoopE ); // LoopE
- AweWrD( AWE_Flt_Start |gChan, 0 // FilterQ=0, RamMode=Normal
- | HWORD(Start), (WORD)Start ); // Start
- AweWrD( AWE_14 |gChan, 0, 0 ); // ???
- AweWrD( AWE_10 |gChan, 0, 0 ); // ???
- AweWrD( AWE_DestV_FC |gChan, 0, 0xFF00 ); // DestVol=0, DestFC=0xFF00
- AweWrD( AWE_CurrV_FC |gChan, 0, 0xFF00 ); // CurrVol=0, CurrFC=0xFF00
- AweWrD( AWE_CurrPitch |gChan, AweLinPitch, 0);// CurrPitch
-
- // Now start the note and envelopes
- AweWrW( AWE_Env2Su_Dcy |gChan, 0x7F01 ); // ENV2 Sustain=max & Decay=min
- }
-